// Copyright 2009 sbva project
//
// This file is part of sbva,
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlecode.sbva;

import com.googlecode.sbva.PropertyAndErrorMessages.ErrorMessage;
import com.googlecode.sbva.PropertyAndErrorMessages.ErrorMessages;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * Allows bean validation constraints to be unit tested.  Use this classs
 * in your JUnit or TestNG unit tests instead of
 * {@link DefaultStrutsBeanValidationAdapter DefaultStrutsBeanValidationAdapter}
 * like this:
 * <p>
 * <blockquote><pre>
 *
 *  &#064;Test
 *  public void showErrors() {
 *
 *     Person person = new Person();
 *
 *     Map&gt;String, String&lt; results = adapter.beanValidationErrorsToString(person01, null);
 *
 *     log.debug(adapter.formatResults(results));
 *
 *     Assert.assertEquals(4, results.size());
 *
 *  }
 *
 * </pre></blockquote>
 *
 *  
 * 
 */
public class ResourceBundleBeanValidationAdapter<T> extends StrutsBeanValidationAdapter {

   private static Log log = LogFactory.getLog(ResourceBundleBeanValidationAdapter.class);
   private List<ResourceBundle> rbs = new ArrayList<ResourceBundle>();
   private LookupProperty lookup = new LookupProperty() {

      public String lookup(String property) {

         for (ResourceBundle rb : rbs) {

            try {

               String errorMessage = rb.getString(property);


               return errorMessage;

            } catch (Exception e) {


               return property;

            }

         }


         return null;

      }
   };

   public ResourceBundleBeanValidationAdapter(ResourceBundle rb) {

      this.rbs.add(rb);

   }

   public ResourceBundleBeanValidationAdapter(List<ResourceBundle> rbs) {

      this.rbs.addAll(rbs);

   }

   public Map<String, String> beanValidationErrorsToString(T model, Class<T>... groups) {

      PropertyAndErrorMessages errors = new PropertyAndErrorMessages();

      beanValidationErrorsToActionErrors(model, lookup, errors, groups);

      Map<String, String> msgs = assembleErrorMessages(errors);

      return msgs;
   }

   public String formatResults(Map<String, String> errors) {

      Set<Entry<String, String>> entrySet = errors.entrySet();

      int len = 0;

      StringBuilder sb = new StringBuilder(0);

      for (Entry<String, String> entry : entrySet) {

         sb.append(entry.getKey() + "={" + entry.getValue() + "}");

         if (++len < entrySet.size()) {

            sb.append(",");

         }

      }

      return sb.toString();

   }

   protected Map<String, String> assembleErrorMessages(PropertyAndErrorMessages errors) {

      Map<String, String> errorMessages = new HashMap<String, String>();

      for (String property : errors.keySet()) {

         ErrorMessages errorMsgs = errors.get(property);

         StringBuilder sb = new StringBuilder();

         for (ErrorMessage errorMsg : errorMsgs) {

            String errorMsgKey = errorMsg.getErrorKey();
            Object[] errorMsgParams = errorMsg.getErrorParameters();

            String errorMsgPattern = lookup.lookup(errorMsgKey);

            String finalMessage = MessageFormat.format(errorMsgPattern, errorMsgParams);

            sb.append(finalMessage + ".  ");
         }

         errorMessages.put(property, sb.toString());


      }

      return errorMessages;

   }

   /**
    *
    * Perform no mapping and just pass throguth the propeerty name.
    *
    * @param propertyName
    * @return propertyName
    */
   protected String mapPropertyToFormInput(String propertyName) {
      if (log.isDebugEnabled()) {
         log.debug("property=" + propertyName);
      }
      return propertyName;
   }

   
}
